{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Sampling from random quantum circuits\n",
    "\n",
    "In this notebook, we will sample from quantum random circuits and compare the distribution we obtain to the theoretical distribution"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%matplotlib inline\n",
    "import matplotlib.pyplot as plt\n",
    "from qiskit import QuantumCircuit, execute, Aer\n",
    "from qiskit.circuit.random import random_circuit"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We define the parameters we are going to use for the random circuits. We also need two backends. The QASM simulator will be used to sample from the circuits and the statevector simualtor will be used to obtain the exact proability of each string that we sample. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "n_circs = 10000\n",
    "n_qubits = 4\n",
    "n_layers = 30\n",
    "freq = []\n",
    "backend_m = Aer.get_backend(\"qasm_simulator\")\n",
    "backend_s = Aer.get_backend(\"statevector_simulator\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now, we generate random circuits and we sample one string from each. Then, we obtain the exact probability of that string."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "for _ in range(n_circs):\n",
    "    #Generate a random circuit \n",
    "    circ = random_circuit(n_qubits, n_layers, measure = False)\n",
    "    #Sample one string from its output\n",
    "    meas = QuantumCircuit(n_qubits,n_qubits)\n",
    "    meas.measure(range(n_qubits),range(n_qubits))\n",
    "    circ_m = circ + meas   \n",
    "    job = execute(circ_m,backend = backend_m, shots = 1, memory = True)\n",
    "    string = job.result().get_memory()[0]\n",
    "    #Compute the exact probability of the string\n",
    "    job = execute(circ, backend = backend_s)\n",
    "    state = job.result().get_statevector()\n",
    "    freq.append(abs(state[int(string,2)])**2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now, we plot the histogram of our samples and compare it to the theoretical distribution"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "xs = np.linspace(0.0, 1.0, 100)\n",
    "dim = 2**n_qubits\n",
    "ys = xs*(dim**2)*np.exp(-dim*xs)\n",
    "plt.hist(freq, bins = 100, density = True)\n",
    "plt.plot(xs, ys, label='Theoretical')\n",
    "plt.show()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
